import socket
import logging
import json
import os
import math
import netifaces
from multiprocessing import Process, Pipe
from laser_simulator import judge_connect
from data_updater import DataUpdater

BUFFER_SIZE = 8192
LATITUDE_KEY = 'lat'
LONGITUDE_KEY = 'lon'
HEIGHT_KEY = 'hei'


def listen_worker(pipe_send, port, buffer_size):
    logging.info('Enter Listener')
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    udp_socket.bind(('0.0.0.0', port))
    while True:
        json_data, client_address = udp_socket.recvfrom(buffer_size)
        print(str(json_data, encoding="utf-8"))
        pipe_send.send(json_data)


def satellite_simulator(broad_port: int, node_id: str, threshold: float):
    print("Enter Simulator.")

    updater = DataUpdater("<broadcast>", broad_port + 1)
    pipe_recv, pipe_send = Pipe()
    listener = Process(target=listen_worker, args=(pipe_send, broad_port, BUFFER_SIZE))
    listener.start()

    while True:
        json_data = pipe_recv.recv()
        data = json.loads(str(json_data, encoding="utf-8"))
        self_data = data[node_id]
        latitude = self_data[LATITUDE_KEY] * 180 / math.pi
        longitude = self_data[LONGITUDE_KEY] * 180 / math.pi
        height = self_data[HEIGHT_KEY]
        logging.info("self.node_id is %s, self.Latitude is %f, Longitude is %f, Sea level height is %f" % (
            node_id, latitude, longitude, height))
        next_conn_state = judge_connect(latitude, threshold)
        interface_array = netifaces.interfaces()
        for i in range(1, 12, 2):
            if "eth" + str(i) in interface_array:
                if next_conn_state:
                    command = "ifconfig %s up" % "eth" + str(i)
                    logging.info("Exec '%s'" % command)
                    os.system(command)
                    status_str = json.dumps({
                        "node_id": node_id,
                        "state": True
                    })
                    updater.broadcast_status(status_str)
                else:
                    command = "ifconfig %s down" % "eth" + str(i)
                    logging.info("Exec '%s'" % command)
                    os.system(command)
                    status_str = json.dumps({
                        "node_id": node_id,
                        "state": False
                    })
                    updater.broadcast_status(status_str)
